package com.ias.common.utils.log;

import com.ias.common.utils.json.JsonUtil;

import java.io.PrintWriter;
import java.io.StringWriter;
import java.util.HashMap;
import java.util.Map;
import java.util.Objects;

/**
 * 异常工具类 - 用于安全打印系统堆栈信息
 * 
 * @author IAS Team
 */
public class ExcpUtil {
    
    /**
     * 默认最大堆栈深度，避免过深的堆栈信息
     */
    private static final int DEFAULT_MAX_STACK_DEPTH = 50;
    
    /**
     * 获取异常的完整堆栈信息字符串
     * 使用 PrintWriter 方式，更高效且完整
     * 
     * @param ex 异常对象
     * @return 堆栈信息字符串，如果异常为null则返回空字符串
     */
    public static String getStackTraceString(Throwable ex) {
        if (ex == null) {
            return "";
        }
        
        try (StringWriter stringWriter = new StringWriter(BufferStringLenth.BUFFER_CAPACITY);
             PrintWriter printWriter = new PrintWriter(stringWriter)) {
            
            ex.printStackTrace(printWriter);
            return stringWriter.toString();
            
        } catch (Exception e) {
            System.err.println("获取堆栈信息失败: " + e.getMessage());
            return fallbackGetStackTrace(ex);
        }
    }
    
    /**
     * 获取限制深度的堆栈信息
     * 
     * @param ex 异常对象
     * @param maxDepth 最大堆栈深度
     * @return 限制深度的堆栈信息
     */
    public static String getStackTraceString(Throwable ex, int maxDepth) {
        if (ex == null) {
            return "";
        }
        
        StackTraceElement[] traceElements = ex.getStackTrace();
        if (traceElements == null || traceElements.length == 0) {
            return ex.toString();
        }
        
        StringBuilder traceBuilder = new StringBuilder(BufferStringLenth.BUFFER_CAPACITY);
        traceBuilder.append(ex.toString()).append(System.lineSeparator());
        
        int depth = Math.min(maxDepth, traceElements.length);
        for (int i = 0; i < depth; i++) {
            traceBuilder.append("\tat ").append(traceElements[i].toString()).append(System.lineSeparator());
        }
        
        if (traceElements.length > maxDepth) {
            traceBuilder.append("\t... ").append(traceElements.length - maxDepth).append(" more");
        }
        
        return traceBuilder.toString();
    }
    
    /**
     * 备用的堆栈信息获取方法
     */
    private static String fallbackGetStackTrace(Throwable ex) {
        StackTraceElement[] traceElements = ex.getStackTrace();
        if (traceElements == null || traceElements.length == 0) {
            return ex.toString();
        }
        
        StringBuilder traceBuilder = new StringBuilder(BufferStringLenth.BUFFER_CAPACITY);
        traceBuilder.append(ex.toString()).append(System.lineSeparator());
        
        for (StackTraceElement traceElement : traceElements) {
            traceBuilder.append("\tat ").append(traceElement.toString()).append(System.lineSeparator());
        }
        
        return traceBuilder.toString();
    }

    /**
     * 获取异常的简要堆栈信息（JSON格式）
     * 
     * @param ex 异常对象
     * @return JSON格式的简要堆栈信息
     */
    public static String getSubStackTrace(Throwable ex) {
        return getSubStackTrace(ex, DEFAULT_MAX_STACK_DEPTH);
    }
    
    /**
     * 获取异常的简要堆栈信息（JSON格式，限制深度）
     * 
     * @param ex 异常对象
     * @param maxDepth 最大堆栈深度
     * @return JSON格式的简要堆栈信息
     */
    public static String getSubStackTrace(Throwable ex, int maxDepth) {
        if (ex == null) {
            return "{}";
        }
        
        try {
            SubTrace subTrace = new SubTrace();
            subTrace.setType(ex.getClass().getName());
            subTrace.setMessage(ex.getMessage());
            
            StackTraceElement[] traceElements = ex.getStackTrace();
            if (traceElements != null && traceElements.length > 0) {
                int depth = Math.min(maxDepth, traceElements.length);
                for (int i = 0; i < depth; i++) {
                    StackTraceElement traceElement = traceElements[i];
                    Map<String, Object> trace = new HashMap<>(4);
                    trace.put("className", traceElement.getClassName());
                    trace.put("lineNumber", traceElement.getLineNumber());
                    trace.put("methodName", traceElement.getMethodName());
                    trace.put("fileName", traceElement.getFileName());
                    subTrace.getTraces().add(trace);
                }
            }
            
            return JsonUtil.toJsonString(subTrace);
            
        } catch (Exception e) {
            System.err.println("获取简要堆栈信息失败: " + e.getMessage());
            return "{\"error\":\"获取堆栈信息失败\",\"type\":\"" + ex.getClass().getName() + "\"}";
        }
    }
    
    /**
     * 构造格式化的错误消息
     * 
     * @param ex 异常对象
     * @return 格式化的错误消息
     */
    public static String buildErrorMessage(Throwable ex) {
        if (ex == null) {
            return "未知异常";
        }
        
        try {
            String exceptionType = ex.getClass().getSimpleName();
            String exceptionMessage = Objects.toString(ex.getMessage(), "无异常消息");
            String stackTrace = getStackTraceString(ex, DEFAULT_MAX_STACK_DEPTH);
            
            return String.format("%s: %s%n%s", exceptionType, exceptionMessage, stackTrace);
            
        } catch (Exception e) {
            System.err.println("构造错误消息失败: " + e.getMessage());
            return "异常信息获取失败: " + ex.getClass().getName();
        }
    }
    
    /**
     * 获取异常的根本原因
     * 
     * @param ex 异常对象
     * @return 根本原因异常
     */
    public static Throwable getRootCause(Throwable ex) {
        if (ex == null) {
            return null;
        }
        
        Throwable cause = ex;
        int depth = 0;
        while (cause.getCause() != null && depth < 100) { // 防止无限循环
            cause = cause.getCause();
            depth++;
        }
        
        return cause;
    }
    
    /**
     * 获取根本原因的消息
     * 
     * @param ex 异常对象
     * @return 根本原因消息
     */
    public static String getRootCauseMessage(Throwable ex) {
        Throwable rootCause = getRootCause(ex);
        return rootCause != null ? Objects.toString(rootCause.getMessage(), "无异常消息") : "未知异常";
    }
    
    /**
     * 检查异常链中是否包含指定类型的异常
     * 
     * @param ex 异常对象
     * @param exceptionClass 要检查的异常类型
     * @return 如果包含返回true，否则返回false
     */
    public static boolean containsException(Throwable ex, Class<? extends Throwable> exceptionClass) {
        if (ex == null || exceptionClass == null) {
            return false;
        }
        
        Throwable current = ex;
        int depth = 0;
        while (current != null && depth < 100) {
            if (exceptionClass.isInstance(current)) {
                return true;
            }
            current = current.getCause();
            depth++;
        }
        
        return false;
    }
    
    /**
     * 获取异常链中第一个指定类型的异常
     * 
     * @param ex 异常对象
     * @param exceptionClass 要查找的异常类型
     * @param <T> 异常类型
     * @return 找到的异常，如果没找到返回null
     */
    @SuppressWarnings("unchecked")
    public static <T extends Throwable> T findException(Throwable ex, Class<T> exceptionClass) {
        if (ex == null || exceptionClass == null) {
            return null;
        }
        
        Throwable current = ex;
        int depth = 0;
        while (current != null && depth < 100) {
            if (exceptionClass.isInstance(current)) {
                return (T) current;
            }
            current = current.getCause();
            depth++;
        }
        
        return null;
    }
    
    /**
     * 安全地获取异常消息，避免空指针
     * 
     * @param ex 异常对象
     * @return 异常消息，如果为null则返回默认消息
     */
    public static String safeGetMessage(Throwable ex) {
        if (ex == null) {
            return "未知异常";
        }
        
        String message = ex.getMessage();
        if (message == null || message.trim().isEmpty()) {
            return ex.getClass().getSimpleName() + " (无详细消息)";
        }
        
        return message;
    }
}
